package com.ming.exception;

import com.ming.enums.ErrorCode;
import com.ming.pojo.vo.Result;
import com.ming.service.MonitoringService;
import com.ming.util.TraceIdUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 统一处理各种异常，返回标准格式的响应结果
 *
 * @author ming
 * @version 1.0
 */
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {

    private final MonitoringService monitoringService;

    // ========== 自定义异常处理 ==========

    /**
     * 业务异常处理
     */
    @ExceptionHandler(BusinessException.class)
    public Result<Object> handleBusinessException(BusinessException e, HttpServletRequest request) {
        log.warn("业务异常 [{}]: {} - {}", TraceIdUtils.getTraceId(), e.getErrorCode(), e.getMessage());

        // 记录异常指标
        monitoringService.recordException(e.getClass().getSimpleName(),
                "code", String.valueOf(e.getCode()),
                "endpoint", request.getRequestURI());

        return Result.error(e.getErrorCode(), e.getMessage(), e.getData())
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 系统异常处理
     */
    @ExceptionHandler(SystemException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> handleSystemException(SystemException e, HttpServletRequest request) {
        log.error("系统异常 [{}]: {} - {}", TraceIdUtils.getTraceId(), e.getErrorCode(), e.getMessage(), e);

        // 发送告警
        monitoringService.sendAlert(e.getErrorCode(), e.getMessage(), e);

        // 记录异常指标
        monitoringService.recordException(e.getClass().getSimpleName(),
                "code", String.valueOf(e.getCode()),
                "endpoint", request.getRequestURI());

        return Result.error(e.getErrorCode(), e.getMessage(), e.getData())
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 参数异常处理
     */
    @ExceptionHandler(ParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleParameterException(ParameterException e, HttpServletRequest request) {
        log.warn("参数异常 [{}]: {} - {}", TraceIdUtils.getTraceId(), e.getErrorCode(), e.getMessage());

        // 记录异常指标
        monitoringService.recordException(e.getClass().getSimpleName(),
                "code", String.valueOf(e.getCode()),
                "endpoint", request.getRequestURI());

        return Result.error(e.getErrorCode(), e.getMessage(), e.getData())
                .traceId(TraceIdUtils.getTraceId());
    }

    // ========== Spring框架异常处理 ==========

    /**
     * 参数校验异常处理（@RequestBody）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleValidationException(MethodArgumentNotValidException e, HttpServletRequest request) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining("; "));

        log.warn("参数校验失败 [{}]: {} - {}", TraceIdUtils.getTraceId(), request.getRequestURI(), message);

        // 记录异常指标
        monitoringService.recordException("ValidationException", "endpoint", request.getRequestURI());

        return Result.error(ErrorCode.BAD_REQUEST, "参数校验失败: " + message)
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 参数校验异常处理（@ModelAttribute）
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleBindException(BindException e, HttpServletRequest request) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining("; "));

        log.warn("参数绑定失败 [{}]: {} - {}", TraceIdUtils.getTraceId(), request.getRequestURI(), message);

        return Result.error(ErrorCode.BAD_REQUEST, "参数校验失败: " + message)
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 参数校验异常处理（@Validated）
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        String message = e.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining("; "));

        log.warn("约束校验失败 [{}]: {} - {}", TraceIdUtils.getTraceId(), request.getRequestURI(), message);

        return Result.error(ErrorCode.BAD_REQUEST, "参数校验失败: " + message)
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 缺失请求参数异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleMissingParameterException(MissingServletRequestParameterException e) {
        log.warn("缺失请求参数 [{}]: {}", TraceIdUtils.getTraceId(), e.getParameterName());

        return Result.error(ErrorCode.BAD_REQUEST, "缺失请求参数: " + e.getParameterName())
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 参数类型不匹配异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleTypeMismatchException(MethodArgumentTypeMismatchException e) {
        String message = String.format("参数 %s 的值 '%s' 无法转换为 %s 类型",
                e.getName(), e.getValue(), e.getRequiredType().getSimpleName());

        log.warn("参数类型不匹配 [{}]: {}", TraceIdUtils.getTraceId(), message);

        return Result.error(ErrorCode.BAD_REQUEST, message)
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * HTTP请求方法不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Result<Object> handleMethodNotAllowedException(HttpRequestMethodNotSupportedException e) {
        log.warn("请求方法不支持 [{}]: {}", TraceIdUtils.getTraceId(), e.getMethod());

        return Result.error(ErrorCode.METHOD_NOT_ALLOWED, "请求方法 " + e.getMethod() + " 不支持")
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * HTTP媒体类型不支持
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    public Result<Object> handleMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        log.warn("媒体类型不支持 [{}]: {}", TraceIdUtils.getTraceId(), e.getContentType());

        return Result.error(ErrorCode.BAD_REQUEST, "媒体类型 " + e.getContentType() + " 不支持")
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * HTTP消息不可读
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleMessageNotReadableException(HttpMessageNotReadableException e) {
        log.warn("HTTP消息不可读 [{}]: {}", TraceIdUtils.getTraceId(), e.getMessage());

        return Result.error(ErrorCode.BAD_REQUEST, "请求体格式错误或缺失")
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 404异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result<Object> handleNoHandlerFoundException(NoHandlerFoundException e) {
        log.warn("接口不存在 [{}]: {} {}", TraceIdUtils.getTraceId(), e.getHttpMethod(), e.getRequestURL());

        return Result.error(ErrorCode.NOT_FOUND, "接口 " + e.getHttpMethod() + " " + e.getRequestURL() + " 不存在")
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 文件上传大小超限
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        log.warn("文件上传大小超限 [{}]: {}", TraceIdUtils.getTraceId(), e.getMessage());

        return Result.error(ErrorCode.FILE_SIZE_EXCEEDED, "上传文件大小超出限制")
                .traceId(TraceIdUtils.getTraceId());
    }

    // ========== 安全相关异常处理 ==========

    /**
     * 认证异常
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<Object> handleAuthenticationException(AuthenticationException e) {
        log.warn("Spring Security认证异常 [{}]: {}", TraceIdUtils.getTraceId(), e.getMessage());

        return Result.error(ErrorCode.UNAUTHORIZED, "认证失败: " + e.getMessage())
                .traceId(TraceIdUtils.getTraceId());
    }

    /**
     * 授权异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result<Object> handleAccessDeniedException(AccessDeniedException e) {
        log.warn("授权异常 [{}]: {}", TraceIdUtils.getTraceId(), e.getMessage());

        return Result.error(ErrorCode.FORBIDDEN, "权限不足，禁止访问")
                .traceId(TraceIdUtils.getTraceId());
    }

    // ========== 数据库异常处理 ==========

    /**
     * 数据库访问异常
     */
    @ExceptionHandler(DataAccessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> handleDataAccessException(DataAccessException e, HttpServletRequest request) {
        log.error("数据库访问异常 [{}]: {}", TraceIdUtils.getTraceId(), request.getRequestURI(), e);

        // 发送告警
        monitoringService.sendAlert(ErrorCode.DATABASE_ERROR, "数据库访问异常: " + e.getMessage(), e);

        return Result.error(ErrorCode.DATABASE_ERROR, "数据处理异常，请稍后重试")
                .traceId(TraceIdUtils.getTraceId());
    }

    // ========== 默认异常处理 ==========

    /**
     * 兜底异常处理
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> handleException(Exception e, HttpServletRequest request) {
        log.error("未知异常 [{}]: {} - {}", TraceIdUtils.getTraceId(), request.getRequestURI(), e.getMessage(), e);

        // 发送告警
        monitoringService.sendAlert(ErrorCode.INTERNAL_SERVER_ERROR, "未知异常: " + e.getMessage(), e);

        // 记录异常指标
        monitoringService.recordException(e.getClass().getSimpleName(),
                "endpoint", request.getRequestURI());

        return Result.error(ErrorCode.INTERNAL_SERVER_ERROR, "系统内部异常，请联系管理员")
                .traceId(TraceIdUtils.getTraceId());
    }
}
